Static Typing Static typing in a programming language means that the translator can determine the type of any variable/parameter/expression/return-type at the time the code is translated from the higher-level programming language. This means that the translator knows all these types BEFORE the code is run, and can guarantee that certain exceptions (related to operations on incompatible types) cannot happen. Python is not a statically-typed language. Java and C++ are. Typically programing language designers trade away some powerful language features to achieve static typing; but in return, programmers get confidence that certain errors cannot ever happen when their code executes. We will briefly examine static typing (which is different from "strong" typing, which says something simpler: the programming language can determine the type of any data when the code executes; Python, Java, and C++ are all strongly typed). In this abreviated lecture note, we will just examine the tip of the iceberg you will be living on for 10 weeks in ICS-45J or ICS-45C. Of course, there are lots of differences (especially in syntax) between these languages, but I believe static typing is one of the biggest differences. I. A simple example: In Python, when we define names we do not specify their types, likewise in function definitions we do not specify the types of parameters or their return types. We can annotate these (even name defintions, such as x : int = 3), but the Python translator does not automatically use these annotations for any purpose (although we have seen how to decorate function and check these specifications when the code runs, in Programming Assignment #4). In Java, when we define names we must specify their types, likewise for function defintions showing parameter typess and a return type. Java will automatically use these specifications to ensure the code is correctly written (in regards to safe types). When we show what a Java name looks like, defined y "int x = 1" we show it as int x in fact, integers in Java are primitives not objects, +-----+ and we show their values INSIDE the boxes, not with | 0 | an arrow. Java does have the type BigInteger, which +-----+ is very similar to the standard int object type in Python. Python Java ---------------------------------------------------------------------------- x = 1 # could write x : int = 1 int x = 1 y = 'a' # could write y : str = 'a' String y = "a" if x < y ... if x < y ... The Python translator (1) translates this code to run on the Python Virtual Machine then (2) the Python run-time system runs it: when trying to execute the if, Python discovers that it cannot compare an int and a str with the < operator (it tries and fails using the dunder methods for both types) and raises an exception. The Java translator (1) translates this code to run on the Java Virtual Machine but discovers that there is no way to compare an int and String: it knows all the prototypes (parameter/return type specifications) for the < operator and finds none to compare ints and strings. So it indicates a "translate-time" (often called compile-time) error related to types not being allowed and refuses to execute the code. In statically-typed languages, a program will not run until all type errors are fixed. In this case, there isn't much difference in what happens: Python translates the code, runs it, and raises an exception showing the code causing the problem; Java compiles the code, finds a type error, and prints a compiler error showing the code causing the problem. A programmer would fix the error and try to re-transate/re-compile. Here is another simple example and how Python/Java treat it. Python Java ---------------------------------------------------------------------------- x = 1 # could write x : int = 1 int x = 1 y = 'a' # could write y : str = 'a' String y = "a" x = 'b' x = "b" ... ... The Python translator (1) translates this code and then (2) the Python run-time system runs it: there are no errors when x is rebound, because there are no restrictions on the type of object x refers to: even if we originally wrote x : int = 1, Python still allows the rebinding. The Java translator (1) translates this code and discovers that there is no way that x should be rebound to 'b' because that would violate the type specification: x was defined to be an int. So Java specifies a compile-time error. II. Syntax Errors Are Treated the Same in Both Languages Syntax errors are discovered identically in both languages. If we had mispelled the keyword "if" as "iff", Python would discover the error while translating the code and report it by showing that line of code; Java would likewise discover and report the error. III. Unexecuted code will never fail (because of a type error) Examine the following code. Assume that block1 in both languages contains perfectly legal code. Note that the print statements in the else part of the if are illegal, because neither language can add an int to a str. Python Java ---------------------------------------------------------------------------- x = 1 # could write x : int = 1 int x = 1 y = 'a' # could write y : str = 'a' String y = "a" if x == 1 if (x == 1) { block1 - any code block1 - any code else: }else{ print(x+y) System.out.println(x+y) } The Python translator (1) translates this code and then (2) the Python run-time system runs it: because x == 1 is True, block1 is executed (and the print is not), so there are no errors. If x's value is changed before the if (or assume we prompted the user to enter a value) so it is not 1, then the else block would execute the print and Python would raise an exception because it cannot add an int to a str. The Java translator (1) translates this code and discovers that trying to add and int and String is not legal (whether or not it will execute the code: it doesn't know at compile-time; OK, here it knows x == 1, but what if we prompted the user for x instead). So, Java specifies a compile-time error. Although we could change x's value or prompt the user for a value to store in x, Java would verify that the result stored in x must still be an int, so the addition would always fail. So, different runs of the Python code may or may not raise an exception. If we tested it only when x was 1, we would never see an exception. So we might think that our code had no bugs, and distribute it, only later to have users complain that certain code raised exceptions. But in Java, the code would be prevented from ever running, by the compile-time error. If we fix all compile-time errors, we know that certain errors caught by Python at run-time will never happen in our Java code when it runs, because static typing finds all such possibly-occuring errors at compile time. For beginning programmers debugging their code, they repeated run their Python code, which raises exceptions that they have to fix. In Java they repeated compile their Java code, which points out type-errors that they have to fix before it will even run their code. When the Python code runs again, it may result in type-errors (if different statements are executed), but once the Java code finally compiles, there can be no type-errors when it runs. So, the debugging process is similar in each language, but different. As someone coming to Python from a statically typed language, it was infuriating that I kept finding errors when the code was running. Someone coming to a statically-typed language from Python will find it infuriating that they have to fix many errors before their program will run. That is the difference. The errors, and the way to fix them, remains the same: when they are fixed (compile- time vs run-time) differs. And statically-typed languages, once code compiles, ensures that no type-errors will occur for the same program in the future. Speaking of input, notice that in Python we can write x = eval(input('Enter anything')) An we could enter an int, string, list, ... The eval function converts the string input into the appropriate value whether int, string, list ... and returns it. Input in Java cannot be so general, because Java must be able to check at compile-time (before it runs the code) that x will store an int value (as it must). It uses a system similar to prompt.for_int('Enter an int'), knowing that the return type of the for_int function is an int. IV. Some Run-Time Errors are not Type Errors Note that both language would raise an exception if we indexed a list illegally or tried to divide by 0. Static typing cannot detect those kinds of errors. So, some errors at run-time can occur in both Java and Python. V. General Expressions Because Java knows the types of all variables (and it knows the types of constants) and the types of all function parameters/return types at compile- time, it knows the types of all values computed (and can ensure functions are called with correctly-typed arguments). For example, if we know s is a String and i is an int, and we define the function count is defined by "int count(String s, char c)" then Java can "prove" that the statement i = count(s+s,'|') - 1 is correct. It knows String+String is String and '|' is a char, so the function count is called with the correct type of arguments. It knows that function returns an int, and that int-int is int, so the expression on the right-hand side of the = is an int. Finally, it knows that i is an int, and int=int is legal. V. Lists in Python, Arrays in Java Note that lists in Python are heterogeneous: they can contain different types, e.g., [1, 'a']. But in Java, arrays (the closest thing to lists) are homogenous: they contains the same type. In Java we might write int [] x = new int[10]; Homogenity is required required, so that for every expression written like x[...] Java will will check ... is an int and know that x[...] will refer to an int (or raise an index-out-of-bounds exception). Python lists are thus more general: we saw examples where lists can contain simple values or other lists. We cannot do something like that in Java*. *In Java we can define an array using a base class; the array can store any classes derived from the base class. But as far a type-checking is concerned, all Java can guarantee is that each element in the list is an instance of the base class. So this approach helps, but not a lot. VI. Python in the Future Python is moving more towards using/checking static typing wherever it can (it already has the syntax to allow annotatations of everything), but because of some powerful things it allows programmers to do, it will never implement fully static typing. I just bought a book yesterday (12/8/20) on the language TypeScript, which is a statically-typed version of JavaScript. The concept of static-typing can be absent, be checked at some level, or be checked completely depdending on the programming language.